package com.a1anwang.okble.demo.ability;

import com.a1anwang.okble.beacon.OKBLEBeacon;
import com.a1anwang.okble.beacon.OKBLEBeaconManager;
import com.a1anwang.okble.beacon.OKBLEBeaconRegion;
import com.a1anwang.okble.common.OKBLEDataUtils;
import com.a1anwang.okble.demo.ResourceTable;
import com.a1anwang.okble.demo.utils.TextUtilsEx;
import com.a1anwang.okble.demo.views.CompleteUUIDInputPopupWindow;
import ohos.aafwk.ability.Ability;
import ohos.aafwk.content.Intent;
import ohos.agp.components.*;
import ohos.agp.utils.Color;
import ohos.eventhandler.EventHandler;
import ohos.eventhandler.EventRunner;
import ohos.eventhandler.InnerEvent;

import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.regex.Matcher;
import java.util.regex.Pattern;

/**
 * Created by a1anwang.com on 2018/8/27.
 */
public class MonitorBeaconRegionAbility extends Ability implements Component.ClickedListener, OKBLEBeaconManager.OKBLEBeaconRegionListener {
    private static final int NOTIFY_DATA = 0;
    EventRunner runner = EventRunner.create(true);// create()的参数是true时，则为托管模式
    MyEventHandler handler = new MyEventHandler(runner);
    ListContainer listView;
    SampleItemProvider provider;
    List<OKBLEBeaconRegion> monitoredRegion = new ArrayList<>();
    Map<String, BeaconRegionState> monitoredRegionState = new HashMap<>();
    OKBLEBeaconManager beaconManager;
    private TextField editMajor;
    private TextField editUuid;
    private TextField editMinor;
    private String beginMajor;
    private String beginMinor;
    private Image btnLeft;

    @Override
    protected void onStart(Intent intent) {
        super.onStart(intent);
        setUIContent(ResourceTable.Layout_ability_monitor_region);
        beaconManager = new OKBLEBeaconManager(this);
        beaconManager.setRegionListener(this);
        initView();
        beaconManager.requestLocationPermission();
    }

    @Override
    protected void onStop() {
        super.onStop();
        beaconManager.stopScan();
    }

    @Override
    public void onClick(Component component) {
        switch (component.getId()) {
            case ResourceTable.Id_btn_add:

                String uuid = editUuid.getText();
                if (!OKBLEDataUtils.isValidUUID(uuid)) {
                    return;
                }
                String majorStr = editMajor.getText().toString();
                String minorStr = editMinor.getText().toString();
                int major = -1;
                int minor = -1;
                if (!TextUtilsEx.isEmpty(majorStr) && TextUtilsEx.isDigitsOnly(majorStr)) {
                    major = Integer.valueOf(majorStr);
                }
                if (!TextUtilsEx.isEmpty(minorStr) && TextUtilsEx.isDigitsOnly(minorStr)) {
                    minor = Integer.valueOf(minorStr);
                }
                OKBLEBeaconRegion okbleBeaconRegion;
                if ((major >= 0 && major <= 65535) && (minor >= 0 && minor <= 65535)) {
                    okbleBeaconRegion = OKBLEBeaconRegion.getInstance(uuid, major, minor);
                } else {
                    if (major >= 0 && major <= 65535) {
                        okbleBeaconRegion = OKBLEBeaconRegion.getInstance(uuid, major);
                    } else {
                        okbleBeaconRegion = OKBLEBeaconRegion.getInstance(uuid);
                    }
                }
                if (monitoredRegionState.containsKey(okbleBeaconRegion.getIdentifier())) {
                    return;
                }
                BeaconRegionState beaconRegionState = new BeaconRegionState();
                beaconRegionState.beaconIdentifier = okbleBeaconRegion.getIdentifier();
                monitoredRegionState.put(beaconRegionState.beaconIdentifier, beaconRegionState);
                monitoredRegion.add(okbleBeaconRegion);
                provider.notifyDataChanged();
                beaconManager.startMonitoringForRegion(okbleBeaconRegion);
                break;
            case ResourceTable.Id_layout_uuid:
                showHexInput();
                break;
            case ResourceTable.Id_btn_left:
                onBackPressed();
                break;
            default:
                break;
        }
    }

    class MyEventHandler extends EventHandler {
        private MyEventHandler(EventRunner runner) {
            super(runner);
        }

        @Override
        public void processEvent(InnerEvent event) {
            super.processEvent(event);
            if (event == null) {
                return;
            }
            int eventId = event.eventId;
            switch (eventId) {
                case NOTIFY_DATA:
                    provider.notifyDataChanged();
                    break;
                default:
                    break;
            }
        }
    }

    @Override
    public void onEnterBeaconRegion(OKBLEBeaconRegion beaconRegion) {
        BeaconRegionState state = monitoredRegionState.get(beaconRegion.getIdentifier());
        if (state != null) {
            state.isIn = true;
        }
        handler.sendEvent(NOTIFY_DATA);
    }

    @Override
    public void onExitBeaconRegion(OKBLEBeaconRegion beaconRegion) {
        BeaconRegionState state = monitoredRegionState.get(beaconRegion.getIdentifier());
        if (state != null) {
            state.isIn = false;
        }
        handler.sendEvent(NOTIFY_DATA);
    }

    @Override
    public void onRangeBeaconsInRegion(List<OKBLEBeacon> beacons) {

    }

    public void initView() {
        editUuid = (TextField) findComponentById(ResourceTable.Id_edit_uuid);
        editMajor = (TextField) findComponentById(ResourceTable.Id_edit_major);
        editMinor = (TextField) findComponentById(ResourceTable.Id_edit_minor);
        findComponentById(ResourceTable.Id_layout_uuid).setClickedListener(this);
        findComponentById(ResourceTable.Id_btn_add).setClickedListener(this);
        btnLeft = (Image) findComponentById(ResourceTable.Id_btn_left);
        btnLeft.setClickedListener(this);
        listView = (ListContainer) findComponentById(ResourceTable.Id_listview);
        provider = new SampleItemProvider(monitoredRegion, this);
        listView.setItemProvider(provider);
        getWindow().setStatusBarColor(Color.getIntColor("#1E90FF"));
        editMajor.addTextObserver(new Text.TextObserver() {
            @Override
            public void onTextUpdated(String s, int i, int i1, int i2) {
                if (!s.isEmpty()) {
                    if (!isNumeric(s)) {
                        editMajor.setText(beginMajor);
                        return;
                    }
                }
                beginMajor = s;
            }
        });
        editMinor.addTextObserver(new Text.TextObserver() {
            @Override
            public void onTextUpdated(String s, int i, int i1, int i2) {
                if (!s.isEmpty()) {
                    if (!isNumeric(s)) {
                        editMinor.setText(beginMinor);
                        return;
                    }
                }
                beginMinor = s;
            }

        });
    }

    private boolean isNumeric(String str) {
        Pattern pattern = Pattern.compile("[0-9]*");
        Matcher isNum = pattern.matcher(str);
        if (!isNum.matches()) {
            return false;
        }
        return true;
    }

    private void showHexInput() {
        CompleteUUIDInputPopupWindow popupWindow = new CompleteUUIDInputPopupWindow(this);
        popupWindow.showAt();
        popupWindow.setInputListener(new CompleteUUIDInputPopupWindow.InputListener() {
            @Override
            public void onInputComplete(String value) {
                TextField editUuid = (TextField) findComponentById(ResourceTable.Id_edit_uuid);
                editUuid.setText(value);
            }
        });
    }

    public class SampleItemProvider extends BaseItemProvider {
        private List<OKBLEBeaconRegion> list;
        private Ability ability;

        /**
         * 构造函数
         *
         * @param list    数据
         * @param ability ability类
         */
        public SampleItemProvider(List<OKBLEBeaconRegion> list, Ability ability) {
            this.list = list;
            this.ability = ability;
        }

        @Override
        public int getCount() {
            return list == null ? 0 : list.size();
        }

        @Override
        public Object getItem(int position) {
            if (list != null && position >= 0 && position < list.size()) {
                return list.get(position);
            }
            return null;
        }

        @Override
        public long getItemId(int position) {
            return position;
        }

        @Override
        public Component getComponent(int position, Component convertView, ComponentContainer componentContainer) {
            ViewHolder viewholder;
            if (convertView == null) {
                viewholder = new ViewHolder();
                convertView = LayoutScatter.getInstance(ability).parse(ResourceTable.Layout_list_item_region, null, false);
                convertView.setTag(viewholder);
                viewholder.tvUuid = (Text) convertView.findComponentById(ResourceTable.Id_tv_uuid);
                viewholder.tvMajor = (Text) convertView.findComponentById(ResourceTable.Id_tv_major);
                viewholder.tvMinor = (Text) convertView.findComponentById(ResourceTable.Id_tv_minor);
                viewholder.tvState = (Text) convertView.findComponentById(ResourceTable.Id_tv_state);
            } else {
                viewholder = (ViewHolder) convertView.getTag();
            }
            OKBLEBeaconRegion okbleBeaconRegion = monitoredRegion.get(position);
            viewholder.tvUuid.setText(okbleBeaconRegion.getUuid());
            viewholder.tvMajor.setText(okbleBeaconRegion.getMajor() < 0 ? "null" : "" + okbleBeaconRegion.getMajor());
            viewholder.tvMinor.setText(okbleBeaconRegion.getMinor() < 0 ? "null" : "" + okbleBeaconRegion.getMinor());
            BeaconRegionState state = monitoredRegionState.get(okbleBeaconRegion.getIdentifier());
            if (state.isIn) {
                viewholder.tvState.setText("In");
                viewholder.tvState.setTextColor(new Color(Color.getIntColor("#87dc49")));
            } else {
                viewholder.tvState.setText("Out");
                viewholder.tvState.setTextColor(new Color(Color.getIntColor("#FF4081")));
            }
            return convertView;
        }
    }

    /**
     * ViewHolder ViewHolder
     *
     * @since 2021-05-14
     */
    protected static final class ViewHolder {
        Text tvUuid;
        Text tvMajor;
        Text tvMinor;
        Text tvState;
    }

    /**
     * BeaconRegionState  BeaconRegionState类
     *
     * @since 2021-05-14
     */
    protected static final class BeaconRegionState {
        String beaconIdentifier;
        boolean isIn;
    }
}
